﻿using EasyModbus;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;
namespace modbus
{
    class Program
    {
        //public static void Main(string[] args)
        //{
        //    ModbusClient modbusClient = new ModbusClient("172.16.0.202", 502);    //Ip-Address and Port of Modbus-TCP-Server
        //    modbusClient.Connect();                                                    //Connect to Server
        //    modbusClient.WriteMultipleCoils(4, new bool[] { true, true, true, true, true, true, true, true, true, true });    //Write Coils starting with Address 5
        //    bool[] readCoils = modbusClient.ReadCoils(9, 10);                        //Read 10 Coils from Server, starting with address 10
        //    int[] readHoldingRegisters = modbusClient.ReadHoldingRegisters(0, 10);    //Read 10 Holding Registers from Server, starting with Address 1
        //    // Console Output
        //    for (int i = 0; i < readCoils.Length; i++)
        //        Console.WriteLine("Value of Coil " + (9 + i + 1) + " " + readCoils[i].ToString());
        //    for (int i = 0; i < readHoldingRegisters.Length; i++)
        //        Console.WriteLine("Value of HoldingRegister " + (i + 1) + " " + readHoldingRegisters[i].ToString());
        //    modbusClient.Disconnect();                                                //Disconnect from Server
        //    Console.Write("Press any key to continue . . . ");
        //    Console.ReadKey(true);
        //}
        public static void Main(string[] args)
        {
            //TcpClient tcpClient;
            modbus.Program mmm = new Program();
            mmm.Open();
            string rData = "";
            for (short i0 = 100; i0 < 850; i0++)
            {
                mmm.ReceiveData(ref rData, 3, i0, 10);

                Console.WriteLine(i0 + ":" + rData.ToString());
                //Console.ReadKey();
                if (i0 == 200) { i0 = 599; }
            }
            Console.ReadKey();
        }
        public TcpClient tcpClient;
        public void Open()
        {
            string ip = "172.16.0.222";
            int port = 502;
            try
            {
                tcpClient = new TcpClient();
                tcpClient.Connect(IPAddress.Parse(ip), port);
                tcpClient.SendTimeout = 500;
                tcpClient.ReceiveTimeout = 100;
                Console.WriteLine("端口:" + port + " ，连接成功");
            }
            catch (SocketException e)
            {
                //LogHelper.WriteLog(e.Message);
                Console.WriteLine("端口:" + port + " ，连接失败"); ;
            }
            //Console.ReadKey();
        }
        /// <summary>
        /// 读取数据 Modbus
        /// </summary>
        /// <param name="rData">结果</param>
        /// <param name="id">设备号</param>
        /// <param name="address">设备地址</param>
        /// <param name="len">长度-多少个设备</param>
        /// <returns>数据读取结果 是否成功</returns>
        public bool ReceiveData(ref string rData, short id, short address, short len)
        {
            try
            {
                short m = Convert.ToInt16(new Random().Next(2, 20));
                rData = null;
                byte[] bs = Receive(m, id, address, len);
                byte[] b = TrimModbus(bs, m, id, len);
                //Console.WriteLine("读取");
                if (b == null) { return false; }
                List<string> data = new List<string>(255);
                for (int i = 0; i < b.Length - 1; i++)
                {
                    if (!Convert.ToBoolean(i & 1))
                    {
                        byte[] temp = new byte[] { b[i + 1], b[i] };
                        data.Add(BitConverter.ToInt16(temp, 0).ToString());

                    }
                }
                // rData = data;
                for (int i = 0; i < data.Count - 1; i++)
                {
                    rData += data[i].ToString() + " ";
                }
                return true;
            }
            catch (Exception e)
            {
                //LogHelper.WriteLog("返回Modbus数据错误" + e.Message);
                Console.WriteLine("读取数据错误");
                return false;
            }
        }
        /// <summary>
        /// 读取 Modbus
        ///00 00 00 00 00 0d  01  03  0A 14 00  14 00  14 00  14 00  14 00
        /// </summary>
        /// <param name="m">标示</param>
        /// <param name="id">设备码</param>
        /// <param name="address">开始地址</param>
        /// <param name="len">设备数量</param>
        /// <returns></returns>
        private byte[] Receive(short m, short id, short address, short len)
        {
            try
            {
                if (tcpClient == null || !tcpClient.Connected) { return null; }
                byte[] data = GetSrcData(m, id, address, len);
                //00 00 00 00 00 06 01 03 00 00 00 05
                tcpClient.Client.Send(data, data.Length, SocketFlags.None);
                int size = len * 2 + 9;
                byte[] rData = new byte[size];
                tcpClient.Client.Receive(rData, size, SocketFlags.None);
                //string t1 = TranBytes(rData);
                return rData;
            }
            catch (SocketException e)
            {
                if (e.ErrorCode != 10004)
                {
                    // LogHelper.WriteLog(e.Message);
                }
                if (tcpClient != null)
                {
                    tcpClient.Close();
                    tcpClient = null;
                }
                return null;
            }
        }
        //发送
        //00 00 00 00 00 06 01 03 00 00 00 05
        /// <summary>
        /// 发送字节数
        /// </summary>
        /// <param name="m"></param>
        /// <param name="len"></param>
        /// <param name="id"></param>
        /// <param name="address"></param>
        /// <returns></returns>
        private byte[] GetSrcData(short m, short id, short add, short len)
        {
            List<byte> data = new List<byte>(255);
            data.AddRange(ValueHelper.Instance.GetBytes(m));                    //            00 01
            data.AddRange(new byte[] { 0x00, 0x00 });                            //            00 00
            data.AddRange(ValueHelper.Instance.GetBytes(Convert.ToInt16(6)));    //字节数      00 06
            data.Add(Convert.ToByte(id));                                        //路由码      01
            data.Add(Convert.ToByte(3));                                        //功能码 3-读  03
            data.AddRange(ValueHelper.Instance.GetBytes(add));                  //开始地址    00 00
            data.AddRange(ValueHelper.Instance.GetBytes(len));                  //设备数量    00 05
            return data.ToArray();
        }
        public class ValueHelper
        {
            #region 大小端判断
            public static bool LittleEndian = false;
            static ValueHelper()
            {
                unsafe
                {
                    int tester = 1;
                    LittleEndian = (*(byte*)(&tester)) == (byte)1;
                }
            }
            #endregion
            #region Factory
            public static ValueHelper _Instance = null;
            internal static ValueHelper Instance
            {
                get
                {
                    if (_Instance == null)
                    {
                        _Instance = LittleEndian ? new LittleEndianValueHelper() : new ValueHelper();
                        //_Instance = new ValueHelper();
                    }
                    return _Instance;
                }
            }
            #endregion
            protected ValueHelper()
            {
            }
            public virtual Byte[] GetBytes(short value)
            {
                return BitConverter.GetBytes(value);
            }
            public virtual Byte[] GetBytes(int value)
            {
                return BitConverter.GetBytes(value);
            }
            public virtual Byte[] GetBytes(float value)
            {
                return BitConverter.GetBytes(value);
            }
            public virtual Byte[] GetBytes(double value)
            {
                return BitConverter.GetBytes(value);
            }
            public virtual short GetShort(byte[] data)
            {
                return BitConverter.ToInt16(data, 0);
            }
            public virtual int GetInt(byte[] data)
            {
                return BitConverter.ToInt32(data, 0);
            }
            public virtual float GetFloat(byte[] data)
            {
                return BitConverter.ToSingle(data, 0);
            }
            public virtual double GetDouble(byte[] data)
            {
                return BitConverter.ToDouble(data, 0);
            }
        }
        internal class LittleEndianValueHelper : ValueHelper
        {
            public override Byte[] GetBytes(short value)
            {
                return this.Reverse(BitConverter.GetBytes(value));
            }
            public override Byte[] GetBytes(int value)
            {
                return this.Reverse(BitConverter.GetBytes(value));
            }
            public override Byte[] GetBytes(float value)
            {
                return this.Reverse(BitConverter.GetBytes(value));
            }
            public override Byte[] GetBytes(double value)
            {
                return this.Reverse(BitConverter.GetBytes(value));
            }
            public virtual short GetShort(byte[] data)
            {
                return BitConverter.ToInt16(this.Reverse(data), 0);
            }
            public virtual int GetInt(byte[] data)
            {
                return BitConverter.ToInt32(this.Reverse(data), 0);
            }
            public virtual float GetFloat(byte[] data)
            {
                return BitConverter.ToSingle(this.Reverse(data), 0);
            }
            public virtual double GetDouble(byte[] data)
            {
                return BitConverter.ToDouble(this.Reverse(data), 0);
            }
            private Byte[] Reverse(Byte[] data)
            {
                Array.Reverse(data);
                return data;
            }
        }
        private byte[] TrimModbus(byte[] d, short m, short id, short len)
        {
            int size = Convert.ToInt32(len) * 2;
            int dLen = size + 9;
            if (d == null || d.Length != dLen || m != Convert.ToInt16(d[1]) || id != Convert.ToInt16(d[6]))
            {
                return null;
            }
            byte[] n = new byte[size];
            Array.Copy(d, 9, n, 0, size);
            return n;
        }
        //public bool Open(string ip, int port)
        //{
        //    try
        //    {
        //        tcpClient = new TcpClient();
        //        tcpClient.Connect(IPAddress.Parse(ip), port);
        //        return true;
        //    }
        //    catch (SocketException e)
        //    {
        //        //LogHelper.WriteLog(e.Message);
        //        return false;
        //    }
        //}
    }
}
